/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package w40k.roster2;
import javax.ws.rs.*;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.util.List;
import java.util.StringTokenizer;
import w40k.data.ActivityState;
/**
 *
 * @author User
 */

@Path("/rosterService")
public class rosterService 
{
    private final int MAX_PERMITTED = 1999;
    private w40k.rules.Rosters data;
    public rosterService() throws JAXBException
    {
        ClassLoader cl = this.getClass().getClassLoader();
        InputStream is = cl.getResourceAsStream("RosterRules.xml");
        JAXBContext jc = JAXBContext.newInstance ("w40k.rules");
        Unmarshaller u = jc.createUnmarshaller ();
        data = (w40k.rules.Rosters) u.unmarshal(is);
    }
    private w40k.rules.Race raceByName(String name)
    {
        w40k.rules.Race curRace = null;
        for (int i = 0; i < data.getArmy().getRace().size(); i++)
        {
            if (data.getArmy().getRace().get(i).getName().equals(name))
            {
                curRace = data.getArmy().getRace().get(i);
                break;
            }
        }
        return curRace;
    }
    
    private w40k.rules.UrUnit unitByName(w40k.rules.Race race, String name)
    {
        for(w40k.rules.UrUnit ur0: race.getUnit())
            if (ur0.getName().equals(name))
                return ur0;
        for(w40k.rules.UnitGroup ug: race.getUnitGroup())
            for(w40k.rules.UrUnit ur1: ug.getUnit())
                if (ur1.getName().equals(name))
                    return ur1;
        return null;
    }
    
    private w40k.rules.UnitGroup unitGroupByUnitName(w40k.rules.Race race, String name)
    {
        for(w40k.rules.UnitGroup ug: race.getUnitGroup())
            for(w40k.rules.UrUnit ur1: ug.getUnit())
                if (ur1.getName().equals(name))
                    return ug;
        return null;
    }

    private int timesUnitPermitted(String ur, w40k.data.Slot slotName, List<w40k.rules.Placement> variants, w40k.data.Armylist incoming)
    {
        int permitted = 0;
        //int contained = containsUnit(slotName,ur);
        for(int i = 0; i<variants.size(); i++)
        {
            w40k.rules.Placement curP = variants.get(i);
            if(!curP.getSlot().value().equals(slotName.getType()))
                continue;
            if (curP.getPermission().size() > 0)
            {
                for(w40k.rules.Placement.Permission p: curP.getPermission())
                    permitted = permitted + incoming.GetUnitCount(p.getByUnit());
            }
            else
            {
                permitted = MAX_PERMITTED;
                break;
            }
        }
        return permitted;
    }
        
    @POST
    @Path("/unit/variant")
    @Produces("application/xml")
    @Consumes("application/xml")
    public w40k.data.Slot activateSlot(w40k.data.Armylist incoming)
    {
        w40k.data.Slot active = null;
        for (int i = 0; i<incoming.getSlot().size(); i++)
        {
            if(incoming.getSlot().get(i).getState() == w40k.data.ActivityState.ACTIVE)
            {
                active = incoming.getSlot().get(i);
                break;
            }
        }
        if (active == null)
            return new w40k.data.Slot();
        active.setChoice(new w40k.data.Slot.Choice());
        w40k.rules.Race curRace = raceByName(incoming.getArmy());
        if (curRace == null)
            return null;
        for(w40k.rules.UrUnit ur: curRace.getUnit())
        {
            int contained = active.GetUnitCount(ur.getName());
            if (ur.getUnique() != null)
            {
                if (incoming.GetUnitCount(ur.getName()) > 0)
                    continue;
            }
            if (timesUnitPermitted(ur.getName(),active,ur.getPlacement(),incoming) > contained)
            {
                w40k.data.Slot.Choice.Item temp = new w40k.data.Slot.Choice.Item();
                temp.setCaption(ur.getName());
                active.getChoice().getItem().add(temp);
            }
        }
        for(w40k.rules.UnitGroup ug:curRace.getUnitGroup())
        {
            if (ug.getUnique() != null)
            {
                boolean placeable = true;
                for (w40k.rules.UrUnit urg: ug.getUnit())
                {
                    if (incoming.GetUnitCount(urg.getName()) > 0)
                    {
                        placeable=false;
                        break;
                    }
                }
                if (!placeable)
                    continue;
            }
            for (w40k.rules.UrUnit urg: ug.getUnit())
            {
                if (timesUnitPermitted(urg.getName(),active,ug.getPlacement(),incoming) + timesUnitPermitted(urg.getName(),active,urg.getPlacement(),incoming) > incoming.GetUnitCount(urg.getName()))
                {
                    w40k.data.Slot.Choice.Item temp = new w40k.data.Slot.Choice.Item();
                    temp.setCaption(urg.getName());
                    active.getChoice().getItem().add(temp);
                }
            }
        }
        return active;
    }

    @POST
    @Path("/unit/finalised")
    @Produces("application/xml")
    @Consumes("application/xml")
    public w40k.data.Armylist revalidateUnitDeleted(w40k.data.Armylist incoming)
    {
        w40k.rules.Race curRace = raceByName(incoming.getArmy());
        if (curRace == null)
            return null;
        for(w40k.data.Slot s: incoming.getSlot())
        {
            w40k.rules.UrUnit check = null;
            w40k.rules.UnitGroup checkGroup = null;
            for(int i = 0; i < s.getUnit().size(); i++)
            {
                if (check == null || !check.getName().equals(s.getUnit().get(i).getType()))
                {
                    check = unitByName(curRace,s.getUnit().get(i).getType());
                    checkGroup = unitGroupByUnitName(curRace,s.getUnit().get(i).getType());
                }
                int totalPermission = 0;
                int totalContainment = 0;
                if (check != null)
                {
                    totalPermission += timesUnitPermitted(check.getName(),s,check.getPlacement(),incoming);
                    
                    if (checkGroup != null)
                    {
                        totalPermission += timesUnitPermitted(check.getName(),s,checkGroup.getPlacement(),incoming);
                        for(w40k.rules.UrUnit ur: checkGroup.getUnit())
                        {
                            totalContainment += s.GetUnitCount(ur.getName());
                        }
                    }
                    else
                        totalContainment += s.GetUnitCount(check.getName());
                }
                if (totalPermission < totalContainment)
                {
                    s.getUnit().remove(i--);
                    s.setState(ActivityState.MUTABLE);
                }
            }
            for(w40k.rules.Mission.Slot sl: data.getOrganization().getMission().get(0).getSlot())
            {
                if(sl.getName().value().equals(s.getType()))
                {
                    if(s.getUnit().size() < sl.getMinRequired() || s.getUnit().size() > sl.getMaxAllowed())
                    {
                        s.setValid(false);
                        incoming.setValid(false);
                    }
                }
            }
        }
        return incoming;
    }
    
    @POST
    @Path("/unit/initial")
    @Produces("application/xml")
    @Consumes("text/plain")
    public w40k.data.Unit getUrUnit(String uRaceName)
    {
        StringTokenizer st = new StringTokenizer(uRaceName,":");
        w40k.rules.Race cRace = raceByName(st.nextToken());
        if (cRace == null)
            return null;
        String uName = st.nextToken();
        w40k.rules.UrUnit cUnit = unitByName(cRace,uName);
        if (cUnit == null)
            return null;
        w40k.data.Unit result = new w40k.data.Unit();
        result.setType(uName);
        w40k.data.Subunit s = new w40k.data.Subunit();

        s.setType(uName);
        s.setQuantity(cUnit.getMin());
        s.setTotal(cUnit.getCost());
        if (cUnit.getMin() != cUnit.getMax())
        {
            w40k.data.Subunit.Qchoice qChoice = new w40k.data.Subunit.Qchoice();
            qChoice.setFrom(cUnit.getMin());
            qChoice.setTo(cUnit.getMax());
            s.setQchoice(qChoice);
            s.setState(ActivityState.MUTABLE);
        }
        else
            s.setState(ActivityState.FIXED);
        if(cUnit.getDefault() != null)
        {
            for(w40k.rules.Itemref iref: cUnit.getDefault().getItemref())
            {
                w40k.data.Equipment eq = new w40k.data.Equipment();
                eq.setType(iref.getRef());
                eq.setState(ActivityState.FROZEN);
                s.getEquipment().add(eq);
            }
        }
        if(cUnit.getOptions().getRule().size() > 0)
        {
            w40k.data.Equipment eq = new w40k.data.Equipment();
            eq.equals("");
            eq.setState(ActivityState.MUTABLE);                
            s.getEquipment().add(eq);
        }
        result.getSubunit().add(s);        
        String sCurSlot = st.nextToken();

        if (sCurSlot != null)
        {
            for(w40k.rules.Mission.Slot sl: data.getOrganization().getMission().get(0).getSlot())
            {
                if(sl.getName().value().equals(sCurSlot))
                {
                    try
                    {
                        int iSlotSize = Integer.parseInt(st.nextToken());
                        if (iSlotSize >= sl.getMinRequired() && iSlotSize< sl.getMaxAllowed())
                            result.setState(ActivityState.MUTABLE);
                        else
                            if (iSlotSize >= sl.getMaxAllowed())
                                result.setState(ActivityState.FIXED);
                            else
                                result.setState(ActivityState.FROZEN);
                    }
                    catch (Exception jb)
                    {
                        jb.printStackTrace();
                    }
                    finally
                    {
                        break;
                    }                                
                }
            }
        }

        return result;
    }
    
    // The Java method will process HTTP GET requests
    @GET 
    // The Java method will produce content identified by the MIME Media
    // type "text/plain"
    @Path("/army/variant")
    @Produces("text/plain")
    public String armyChoice() 
    {
        String result = new String();
        // Return some cliched textual content
        for(w40k.rules.Race rce: data.getArmy().getRace())
        {
            result = result + rce.getName() + " ";
        }
        return result;
    }
    

    @POST
    @Path("/army/initial")
    @Produces("application/xml")
    @Consumes("text/plain")
    public w40k.data.Armylist getInitial(String race) 
    {
        //TODO write your implementation code here:
        ClassLoader cl = this.getClass().getClassLoader();
        InputStream is = cl.getResourceAsStream("RosterRules.xml");
        try
        {
            w40k.data.Armylist ar = new w40k.data.Armylist();
            ar.setArmy(race);
            ar.setValid(false);
            String result = "";
            for(w40k.rules.Mission.Slot slt: data.getOrganization().getMission().get(0).getSlot())
            {
                w40k.data.Slot temp = new w40k.data.Slot();
                temp.setType(slt.getName().value());
                temp.setState(w40k.data.ActivityState.MUTABLE);
                if (0 >= slt.getMinRequired())
                    temp.setValid(true);
                else
                    temp.setValid(false);
                ar.getSlot().add(temp);
            }
            return ar;
        }
        catch (Exception jb)
        {
            jb.printStackTrace();
        }
        return null;
    }
    
    //@POST
    //@Path("/upgrade/variants")
}